﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;
using EPiServer.Core;
using EPiServer.PlugIn;
using TemplateFoundation.Configuration;
using TemplateFoundation.Exceptions;
using TemplateFoundation.Tags;
using TemplateFoundation.WebControls.PropertyControls;

namespace TemplateFoundation.CustomProperties
{
    /// <summary>
    /// Property for managing tags for a page
    /// </summary>
    [Serializable]
    [PageDefinitionTypePlugIn(
        DefaultEnabled = true,
        DisplayName = "Tag collection",
        Description = "Used to assign tags to a page"
        )]
    public class PropertyTags : PropertyData
    {
        private TagCollection _tags;

        /// <summary>
        /// Creates a new empty tag collection
        /// </summary>
        public PropertyTags()
        {
            _tags = new TagCollection();
        }

        /// <summary>
        /// Creates a new property tag collection based on the specified tags
        /// </summary>
        /// <param name="tags"></param>
        public PropertyTags(IEnumerable<Tag> tags) : base(false)
        {
            _tags = new TagCollection();

            foreach(var tag in tags)
            {
                _tags.Add(tag);
            }
        }

        /// <summary>
        /// Creates the property control.
        /// </summary>
        /// <returns></returns>
        public override IPropertyControl CreatePropertyControl()
        {
            return new PropertyTagsControl();
        }

        /// <summary>
        /// Parses a pipe-separated list of tags
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static PropertyTags Parse(string value)
        {
            if (QualifyAsNullString(value))
            {
                return new PropertyTags();
            }

            try
            {
                return PageReference.IsNullOrEmpty(Settings.Instance.TagsContainer) ?
                       new PropertyTags() : 
                       new PropertyTags(value.Split('|').Select(tag => new Tag(tag)).ToList());
            }
            catch (TemplateFoundationException)
            {
                throw;
            }
            catch
            {
                throw new InvalidPropertyValueException(typeof(PropertyTags).ToString(), value);
            }
        }

        /// <summary>
        /// Parses to object.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public override PropertyData ParseToObject(string value)
        {
            return Parse(value);
        }

        /// <summary>
        /// Parses to self.
        /// </summary>
        /// <param name="value">The value.</param>
        public override void ParseToSelf(string value)
        {
            Value = Parse(value).Value;
        }

        /// <summary>
        /// Sets the default value.
        /// </summary>
        protected override void SetDefaultValue()
        {
            ThrowIfReadOnly();
            _tags=new TagCollection();
        }


        /// <summary>
        /// Gets or sets the tags.
        /// </summary>
        /// <value>The tags.</value>
        [XmlIgnore]
        public TagCollection Tags
        {
            get
            {
                return _tags;
            }
            set
            {
                ThrowIfReadOnly();

                if ((_tags != value) || IsNull)
                {
                    _tags = value;
                    Modified();
                }
            }
        }

        /// <summary>
        /// Gets the type of the property value.
        /// </summary>
        /// <value>The type of the property value.</value>
        public override Type PropertyValueType
        {
            get
            {
                return typeof(TagCollection);
            }
        }

        /// <summary>
        /// Gets the native EPiServer property type.
        /// </summary>
        /// <value>The type.</value>
        public override PropertyDataType Type
        {
            get
            {
                return PropertyDataType.String;
            }
        }

        /// <summary>
        /// Gets or sets the tag collection
        /// </summary>
        /// <remarks>Property can be set using a separated</remarks>
        /// <exception cref="TemplateFoundationException"></exception>
        public override object Value
        {
            get
            {
                if (IsNull)
                {
                    return new TagCollection();
                }

                return _tags;

            }
            set
            {
                SetPropertyValue(value, delegate
                {
                    if (value is TagCollection)
                    {
                        Tags = (TagCollection)value;

                        return;
                    }

                    if(value is string)
                    {
                        ParseToSelf((string)value);

                        return;
                    }

                    throw new TemplateFoundationException("Property value must be a TagCollection or String object");
                });
            }
        }

        /// <summary>
        /// Gets a value indicating whether the tag collection is null or if it doesn't contain any values
        /// </summary>
        public override bool IsNull
        {
            get
            {
                return !(_tags != null && _tags.Any());
            }
        }

        /// <summary>
        /// Performs an implicit conversion from <see cref="TemplateFoundation.CustomProperties.PropertyTags"/> to <see cref="System.String"/>.
        /// </summary>
        /// <param name="prop">The prop.</param>
        /// <returns>The result of the conversion.</returns>
        public static implicit operator string(PropertyTags prop)
        {
            return prop.Tags.ToString();
        }

        /// <summary>
        /// Performs an implicit conversion from <see cref="System.String"/> to <see cref="TemplateFoundation.CustomProperties.PropertyTags"/>.
        /// </summary>
        /// <param name="str">The STR.</param>
        /// <returns>The result of the conversion.</returns>
        public static implicit operator PropertyTags(string str)
        {
            var prop = new PropertyTags();

            var tags = str.Split('|');

            foreach (var tag in tags)
            {
                if(!string.IsNullOrEmpty(tag))
                {
                    prop.Tags.Add(new Tag(tag));
                }
            }

            return prop;
        }
    }
}
